package main
import (
	"fmt"
)
//定义一个结构体，结构体是一个值类型~！
//结构体的大小写也可以设计的他的作用域，大写开头就可以被其他包引用！！！
type Cat struct {
	Name string
	Age int
	Color string
}
//结构体的内存布局是 ： 一个实例有一块空间，里面分别有多个变量小空间

//特殊字段的用法：（指针，切片slice，Map）默认值都是nil
type Person struct {
	Name string
	Age int
	Scores [5]int
	ptr *int
	slice []int  //通过append添加切片数据，或者先make后在直接像数组一样赋值数据
	kvmap map[string]string
}

func main(){
	var cat1 Cat  //定义一个实例
	cat1.Name = "朵朵"
	cat1.Age = 1
	cat1.Color = "grey"
	fmt.Println("The cat'info is : ",cat1)

	cat6 := Cat{"asdasdasdassad",100,"dassdasdsadads"}

	var person Person
	person.Name = "fmx"
	//通过append添加切片数据，或者先make后在直接像数组一样赋值数据
	person.slice = append(person.slice,100)   
	fmt.Println("The person'info is : ",person)
	//map需要先make后在使用
	person.kvmap = make(map[string]string) 
	person.kvmap["lover"] = "lsx"
	fmt.Println("The person'info is : ",person)	

	//声明实例方式2：
	cat2 := Cat{"无常",500,"黑白"}
	fmt.Println("new cat is : ",cat2)

	//声明实例方式3：通过new一个对象指针
	var cat3 *Cat = new(Cat)
	(*cat3).Name = "小白"  //go设计者为方便我们开发，底层允许我们将(*cat3).Name 写成 cat3.Name，因为底层会加上取值运算的
	cat3.Name = "小少爷"
	(*cat3).Age = 22
	fmt.Println("cat3 : ",*cat3)

	//声明实例方式4：-{}
	var cat4 *Cat = &Cat{}   //也可以写成直接赋值 ； &Cat{"...",0}
	//同样可以简写成 cat4.Name = "..." 原理同上！
	cat4.Name = "猪猪"
	cat4.Age = 22
	fmt.Println("cat4 : ",*cat4)

	var cat5 *Cat = &Cat{"大白",100,"白"}
	fmt.Println("cat5 : ",*cat5)


	//指针的使用   //ptr 保存了cat1的地址！  ptr 共享了与 cat1 一样的空间 可以通过ptr来修改cat1的值
	var ptr *Cat = &cat1
	fmt.Printf("ptr : %p\n",ptr)
	fmt.Printf("cat1 : %p\n",&cat1)
	fmt.Printf("ptr的值 : %v\n",*ptr)
	//不能写成 *ptr.Age 这样会报错！因为 . 的运算符比 * 高，所有不会表达成 指针 *ptr


	fmt.Printf("cat1 address :%p\n",&cat1)
	fmt.Printf("cat6 address :%p\n",&cat6)
	fmt.Printf("cat2 address :%p\n",&cat2)
	
	//测试地址内存分布
	var c Cat
	c.Age = 100
	c.Name = "abc"
	fmt.Printf("c :%v\n",c)	
	fmt.Printf("c address :%p\n",&c)
	fmt.Printf("c'Name' address :%p\n",&c.Name)	
	fmt.Printf("c'Age' address :%p\n",&c.Age)
	fmt.Printf("c'Color' address :%p\n",&c.Color)	
}